using System.Net.Http.Headers;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NotifyCenter.Sender.Options;
using NotifyCenter.Sender.ResponseModels;

namespace NotifyCenter.Sender;

/// <summary>
/// Sends common Feishu group messages via open API (chat/v4/send).
/// </summary>
public class FeishuSender : ISender
{
    private const string DefaultMessageEndpoint = "https://open.feishu.cn/open-apis/chat/v4/send";
    private readonly HttpClient _httpClient;

    public string Type => "FeishuCommonMessage";

    public FeishuSender()
    {
        _httpClient = new HttpClient
        {
            Timeout = TimeSpan.FromSeconds(30)
        };
    }

    public async Task SendAsync(string configurationJson, string receiver, string content, CancellationToken cancellationToken = default)
    {
        var config = DeserializeConfiguration(configurationJson);
        var receiverOptions = DeserializeReceiver(receiver);

        var accessToken = await GetTenantAccessTokenAsync(config, cancellationToken);
        var msgType = DetermineMessageType(receiverOptions.MessageType);
        var payloadContent = BuildContent(msgType, content);

        var requestBody = new FeishuSendMessageRequest
        {
            ChatId = receiverOptions.ChatId,
            MsgType = msgType,
            Content = payloadContent
        };

        var requestJson = JsonConvert.SerializeObject(requestBody);
        using var requestMessage = new HttpRequestMessage(HttpMethod.Post, DefaultMessageEndpoint)
        {
            Content = new StringContent(requestJson, Encoding.UTF8, "application/json")
        };
        requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);

        using var response = await _httpClient.SendAsync(requestMessage, cancellationToken);
        response.EnsureSuccessStatusCode();

        var responseContent = await response.Content.ReadAsStringAsync(cancellationToken);
        var sendResponse = JsonConvert.DeserializeObject<FeishuSendMessageResponse>(responseContent)
                           ?? throw new InvalidOperationException("Unexpected Feishu send response.");

        if (!sendResponse.IsSuccess)
        {
            throw new InvalidOperationException($"Feishu send failed: Code={sendResponse.Code}, Msg={sendResponse.Message}");
        }
    }

    private static FeishuSenderConfiguration DeserializeConfiguration(string configurationJson)
    {
        if (string.IsNullOrWhiteSpace(configurationJson))
        {
            throw new ArgumentNullException(nameof(configurationJson), "configurationJson cannot be null or empty.");
        }

        var config = JsonConvert.DeserializeObject<FeishuSenderConfiguration>(configurationJson)
                     ?? throw new InvalidOperationException("Invalid configurationJson: failed to deserialize FeishuSenderConfiguration.");

        if (config.TenantAccessToken == null)
        {
            throw new InvalidOperationException("configurationJson is missing tenant_access_token.");
        }

        var tokenConfig = config.TenantAccessToken;
        if (string.IsNullOrWhiteSpace(tokenConfig.BaseUrl))
        {
            throw new InvalidOperationException("tenant_access_token.base_url cannot be empty.");
        }

        if (string.IsNullOrWhiteSpace(tokenConfig.LoginUri))
        {
            throw new InvalidOperationException("tenant_access_token.login_uri cannot be empty.");
        }

        if (string.IsNullOrWhiteSpace(tokenConfig.AppId))
        {
            throw new InvalidOperationException("tenant_access_token.app_id cannot be empty.");
        }

        if (string.IsNullOrWhiteSpace(tokenConfig.AppSecret))
        {
            throw new InvalidOperationException("tenant_access_token.app_secret cannot be empty.");
        }

        return config;
    }

    private static FeishuCommonMessageReceiver DeserializeReceiver(string receiver)
    {
        if (string.IsNullOrWhiteSpace(receiver))
        {
            throw new ArgumentNullException(nameof(receiver), "receiver cannot be null or empty.");
        }

        if (!receiver.TrimStart().StartsWith("{", StringComparison.Ordinal))
        {
            return new FeishuCommonMessageReceiver
            {
                ChatId = receiver
            };
        }

        try
        {
            var options = JsonConvert.DeserializeObject<FeishuCommonMessageReceiver>(receiver);
            if (string.IsNullOrWhiteSpace(options?.ChatId))
            {
                throw new InvalidOperationException("receiver JSON must include chat_id.");
            }

            return options!;
        }
        catch (JsonException ex)
        {
            throw new InvalidOperationException("receiver must be chat_id string or JSON like {\"chat_id\":\"xxx\"}.", ex);
        }
    }

    private static string DetermineMessageType(string? rawType)
    {
        return string.IsNullOrWhiteSpace(rawType)
            ? "text"
            : rawType.Trim().ToLowerInvariant();
    }

    private static string BuildContent(string msgType, string content)
    {
        if (string.IsNullOrWhiteSpace(content))
        {
            throw new ArgumentNullException(nameof(content), "content cannot be null or empty.");
        }

        if (msgType == "text")
        {
            var textContent = new FeishuTextContent { Text = content };
            return JsonConvert.SerializeObject(textContent);
        }

        if (!IsValidJson(content))
        {
            throw new InvalidOperationException($"content must be a valid JSON string for msg_type '{msgType}'.");
        }

        return content;
    }

    private static bool IsValidJson(string payload)
    {
        try
        {
            JToken.Parse(payload);
            return true;
        }
        catch (JsonReaderException)
        {
            return false;
        }
    }

    private async Task<string> GetTenantAccessTokenAsync(FeishuSenderConfiguration config, CancellationToken cancellationToken)
    {
        var tokenConfig = config.TenantAccessToken;
        var baseUrl = tokenConfig.BaseUrl.TrimEnd('/');
        var loginUri = tokenConfig.LoginUri.TrimStart('/');
        var query = $"app_id={Uri.EscapeDataString(tokenConfig.AppId)}&app_secret={Uri.EscapeDataString(tokenConfig.AppSecret)}";
        var requestUrl = $"{baseUrl}/{loginUri}?{query}";

        using var requestMessage = new HttpRequestMessage(HttpMethod.Post, requestUrl);
        using var response = await _httpClient.SendAsync(requestMessage, cancellationToken);
        response.EnsureSuccessStatusCode();

        var rawResponse = await response.Content.ReadAsStringAsync(cancellationToken);
        var tokenResponse = JsonConvert.DeserializeObject<FeishuTenantAccessTokenResponse>(rawResponse)
                            ?? throw new InvalidOperationException("Failed to deserialize tenant access token response.");

        if (!tokenResponse.IsSuccess)
        {
            throw new InvalidOperationException($"Feishu token request failed: Code={tokenResponse.Code}, Msg={tokenResponse.Message}");
        }

        return tokenResponse.TenantAccessToken;
    }
}
